﻿package core.image
{

    public class Spline3 extends Object
    {
        private var __t:Array;
        private var __y:Array;
        private var __u:Array;
        private var __v:Array;
        private var __h:Array;
        private var __b:Array;
        private var __z:Array;
        private var __hInv:Array;
        private var __delta:Number;
        private var __knots:Number;
        private var __invalidate:Boolean;

        public function Spline3()
        {
            this.__t = new Array();
            this.__y = new Array();
            this.__u = new Array();
            this.__v = new Array();
            this.__h = new Array();
            this.__b = new Array();
            this.__z = new Array();
            this.__hInv = new Array();
            this.__invalidate = true;
            this.__delta = 0;
            this.__knots = 0;
            return;
        }// end function

        public function get knotCount() : Number
        {
            return this.__knots;
        }// end function

        public function get knots() : Array
        {
            var _loc_2:uint = 0;
            var _loc_1:* = new Array();
            while (_loc_2 < this.__knots)
            {
                
                _loc_1.push({X:this.__t[_loc_2], Y:this.__y[_loc_2]});
                _loc_2 = _loc_2 + 1;
            }
            return _loc_1;
        }// end function

        public function addControlPoint(Number:Number, Number:Number) : void
        {
            var _loc_3:uint = 0;
            this.__invalidate = true;
            if (this.__t.length == 0)
            {
                this.__t.push(Number);
                this.__y.push(Number);
                var _loc_4:String = this;
                var _loc_5:* = this.__knots + 1;
                _loc_4.__knots = _loc_5;
            }
            else if (Number > this.__t[(this.__knots - 1)])
            {
                this.__t.push(Number);
                this.__y.push(Number);
                var _loc_4:String = this;
                var _loc_5:* = this.__knots + 1;
                _loc_4.__knots = _loc_5;
            }
            else if (Number < this.__t[0])
            {
                this.__insert(Number, Number, 0);
            }
            else if (this.__knots > 1)
            {
                _loc_3 = 0;
                while (_loc_3 < (this.__knots - 1))
                {
                    
                    if (Number > this.__t[_loc_3] && Number < this.__t[(_loc_3 + 1)])
                    {
                        this.__insert(Number, Number, (_loc_3 + 1));
                    }
                    _loc_3 = _loc_3 + 1;
                }
            }
            return;
        }// end function

        private function __insert(Number:Number, Number:Number, Number:Number) : void
        {
            var _loc_4:int = 0;
            var _loc_5:* = this.__knots - 1;
            while (_loc_5 >= Number)
            {
                
                this.__t[(_loc_5 + 1)] = this.__t[_loc_5];
                this.__y[(_loc_5 + 1)] = this.__y[_loc_5];
                _loc_5 = _loc_5 - 1;
            }
            this.__t[Number] = Number;
            this.__y[Number] = Number;
            var _loc_6:String = this;
            var _loc_7:* = this.__knots + 1;
            _loc_6.__knots = _loc_7;
            return;
        }// end function

        private function __remove(Number:Number) : void
        {
            var _loc_2:* = Number;
            while (_loc_2 < this.__knots)
            {
                
                this.__t[_loc_2] = this.__t[(_loc_2 + 1)];
                this.__y[_loc_2] = this.__y[(_loc_2 + 1)];
                _loc_2 = _loc_2 + 1;
            }
            this.__t.pop();
            this.__y.pop();
            var _loc_3:String = this;
            var _loc_4:* = this.__knots - 1;
            _loc_3.__knots = _loc_4;
            return;
        }// end function

        public function removePointAt(Number:uint) : void
        {
            this.__remove(Number);
            this.__invalidate = true;
            return;
        }// end function

        public function moveControlPoint(Number:uint, Number:Number, Number:Number) : void
        {
            this.__t[Number] = Number;
            this.__y[Number] = Number;
            this.__invalidate = true;
            return;
        }// end function

        public function deleteAllKnots() : void
        {
            this.__t.splice(0);
            this.__y.splice(0);
            this.__knots = 0;
            this.__invalidate = true;
            return;
        }// end function

        public function removeKnotAtX(Number:Number) : void
        {
            var _loc_3:int = 0;
            var _loc_2:* = -1;
            while (_loc_3 < this.__knots)
            {
                
                if (this.__t[_loc_3] == Number)
                {
                    _loc_2 = _loc_3;
                    break;
                }
                _loc_3++;
            }
            if (_loc_2 != -1)
            {
                this.__remove(_loc_2);
                this.__invalidate = true;
            }
            return;
        }// end function

        public function eval(__invalidate:Number) : Number
        {
            var _loc_2:uint = 0;
            var _loc_3:uint = 0;
            var _loc_4:Number = NaN;
            var _loc_5:Number = NaN;
            var _loc_6:Number = NaN;
            var _loc_7:Number = NaN;
            if (this.__knots == 0)
            {
                return NaN;
            }
            if (this.__knots == 1)
            {
                return this.__y[0];
            }
            if (this.__invalidate)
            {
                this.__computeZ();
            }
            _loc_2 = 0;
            this.__delta = __invalidate - this.__t[0];
            _loc_3 = this.__knots - 2;
            while (_loc_3 >= 0)
            {
                
                if (__invalidate >= this.__t[_loc_3])
                {
                    this.__delta = __invalidate - this.__t[_loc_3];
                    _loc_2 = _loc_3;
                    break;
                }
                _loc_3 = _loc_3 - 1;
            }
            _loc_4 = (this.__y[(_loc_2 + 1)] - this.__y[_loc_2]) * this.__hInv[_loc_2] - this.__h[_loc_2] * (this.__z[(_loc_2 + 1)] + 2 * this.__z[_loc_2]) * (1 / 6);
            _loc_5 = 0.5 * this.__z[_loc_2] + this.__delta * (this.__z[(_loc_2 + 1)] - this.__z[_loc_2]) * (1 / 6) * this.__hInv[_loc_2];
            _loc_6 = _loc_4 + this.__delta * _loc_5;
            _loc_7 = this.__y[_loc_2] + this.__delta * _loc_6;
            return _loc_7;
        }// end function

        private function __computeZ() : void
        {
            var _loc_1:uint = 0;
            while (_loc_1 < (this.__knots - 1))
            {
                
                this.__h[_loc_1] = this.__t[(_loc_1 + 1)] - this.__t[_loc_1];
                this.__hInv[_loc_1] = 1 / this.__h[_loc_1];
                this.__b[_loc_1] = (this.__y[(_loc_1 + 1)] - this.__y[_loc_1]) * this.__hInv[_loc_1];
                _loc_1 = _loc_1 + 1;
            }
            this.__u[1] = 2 * (this.__h[0] + this.__h[1]);
            this.__v[1] = 6 * (this.__b[1] - this.__b[0]);
            _loc_1 = 2;
            while (_loc_1 < (this.__knots - 1))
            {
                
                this.__u[_loc_1] = 2 * (this.__h[_loc_1] + this.__h[(_loc_1 - 1)]) - this.__h[(_loc_1 - 1)] * this.__h[(_loc_1 - 1)] / this.__u[(_loc_1 - 1)];
                this.__v[_loc_1] = 6 * (this.__b[_loc_1] - this.__b[(_loc_1 - 1)]) - this.__h[(_loc_1 - 1)] * this.__v[(_loc_1 - 1)] / this.__u[(_loc_1 - 1)];
                _loc_1 = _loc_1 + 1;
            }
            this.__z[(this.__knots - 1)] = 0;
            _loc_1 = this.__knots - 2;
            while (_loc_1 >= 1)
            {
                
                this.__z[_loc_1] = (this.__v[_loc_1] - this.__h[_loc_1] * this.__z[(_loc_1 + 1)]) / this.__u[_loc_1];
                _loc_1 = _loc_1 - 1;
            }
            this.__z[0] = 0;
            this.__invalidate = false;
            return;
        }// end function

    }
}
